Beispiel #1
0
void sinsp_container_manager::dump_containers(scap_dumper_t* dumper)
{
	for(unordered_map<string, sinsp_container_info>::const_iterator it = m_containers.begin(); it != m_containers.end(); ++it)
	{
		if(container_to_sinsp_event(container_to_json(it->second), &m_inspector->m_meta_evt))
		{
			int32_t res = scap_dump(m_inspector->m_h, dumper, m_inspector->m_meta_evt.m_pevt, m_inspector->m_meta_evt.m_cpuid, 0);
			if(res != SCAP_SUCCESS)
			{
				throw sinsp_exception(scap_getlasterr(m_inspector->m_h));
			}
		}
	}
}
Beispiel #2
0
bool sinsp_container_manager::resolve_container(sinsp_threadinfo* tinfo, bool query_os_for_missing_info)
{
	ASSERT(tinfo);
	bool valid_id = false;
	sinsp_container_info container_info;

	for(auto it = tinfo->m_cgroups.begin(); it != tinfo->m_cgroups.end(); ++it)
	{
		string cgroup = it->second;
		size_t pos;

		//
		// Non-systemd Docker
		//
		pos = cgroup.find_last_of("/");
		if(pos != string::npos)
		{
			if(cgroup.length() - pos - 1 == 64 &&
				cgroup.find_first_not_of("0123456789abcdefABCDEF", pos + 1) == string::npos) 
			{
				container_info.m_type = CT_DOCKER;
				container_info.m_id = cgroup.substr(pos + 1, 12);
				valid_id = true;
				break;
			}
		}

		//
		// systemd Docker
		//
		pos = cgroup.find("docker-");
		if(pos != string::npos)
		{
			size_t pos2 = cgroup.find(".scope");
			if(pos2 != string::npos &&
				pos2 - pos - sizeof("docker-") + 1 == 64)
			{
				container_info.m_type = CT_DOCKER;
				container_info.m_id = cgroup.substr(pos + sizeof("docker-") - 1, 12);
				valid_id = true;
				break;
			}
		}

		//
		// Non-systemd libvirt-lxc
		//
		pos = cgroup.find(".libvirt-lxc");
		if(pos != string::npos &&
			pos == cgroup.length() - sizeof(".libvirt-lxc") + 1)
		{
			size_t pos2 = cgroup.find_last_of("/");
			if(pos2 != string::npos)
			{
				container_info.m_type = CT_LIBVIRT_LXC;
				container_info.m_id = cgroup.substr(pos2 + 1, pos - pos2 - 1);
				valid_id = true;
				break;
			}
		}

		//
		// systemd libvirt-lxc
		//
		pos = cgroup.find("-lxc\\x2");
		if(pos != string::npos)
		{
			size_t pos2 = cgroup.find(".scope");
			if(pos2 != string::npos &&
				pos2 == cgroup.length() - sizeof(".scope") + 1)
			{
				container_info.m_type = CT_LIBVIRT_LXC;
				container_info.m_id = cgroup.substr(pos + sizeof("-lxc\\x2"), pos2 - pos - sizeof("-lxc\\x2"));
				valid_id = true;
				break;
			}
		}

		//
		// Legacy libvirt-lxc
		//
		pos = cgroup.find("/libvirt/lxc/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_LIBVIRT_LXC;
			container_info.m_id = cgroup.substr(pos + sizeof("/libvirt/lxc/") - 1);
			valid_id = true;
			break;
		}

		//
		// Non-systemd LXC
		//
		pos = cgroup.find("/lxc/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_LXC;
			container_info.m_id = cgroup.substr(pos + sizeof("/lxc/") - 1);
			valid_id = true;
			break;
		}

		//
		// Mesos
		//
		pos = cgroup.find("/mesos/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_MESOS;
			container_info.m_id = cgroup.substr(pos + sizeof("/mesos/") - 1);
			valid_id = true;
			set_mesos_task_id(&container_info, tinfo);
			break;
		}
	}

	string rkt_podid, rkt_appname;
	if(!valid_id)
	{
		// Try parsing from process root,
		// Strings used to detect rkt stage1-cores pods
		static const string COREOS_PREFIX = "/opt/stage2/";
		static const string COREOS_APP_SUFFIX = "/rootfs";
		static const string COREOS_PODID_VAR = "container_uuid=";

		auto prefix = tinfo->m_root.find(COREOS_PREFIX);
		if(prefix != string::npos)
		{
			auto suffix = tinfo->m_root.find(COREOS_APP_SUFFIX, prefix);
			if(suffix != string::npos)
			{
				rkt_appname = tinfo->m_root.substr(prefix + COREOS_PREFIX.size(), suffix - prefix - COREOS_PREFIX.size());
				// It is a rkt pod with stage1-coreos
				sinsp_threadinfo* tinfo_it = tinfo;
				while(!valid_id && tinfo_it != nullptr)
				{
					for(const auto& env_var : tinfo_it->m_env)
					{
						auto container_uuid_pos = env_var.find(COREOS_PODID_VAR);
						if(container_uuid_pos == 0)
						{
							rkt_podid = env_var.substr(COREOS_PODID_VAR.size());
							container_info.m_type = CT_RKT;
							container_info.m_id = rkt_podid + ":" + rkt_appname;
							container_info.m_name = rkt_appname;
							valid_id = true;
							break;
						}
					}
					tinfo_it = tinfo_it->get_parent_thread();
				}
			}
		}
		else
		{
			// String used to detect stage1-fly pods
			static const string FLY_PREFIX = "/var/lib/rkt/pods/run/";
			static const string FLY_PODID_SUFFIX = "/stage1/rootfs/opt/stage2/";
			static const string FLY_APP_SUFFIX = "/rootfs";

			auto prefix = tinfo->m_root.find(FLY_PREFIX);
			if(prefix != string::npos)
			{
				auto podid_suffix = tinfo->m_root.find(FLY_PODID_SUFFIX, prefix+FLY_PREFIX.size());
				if(podid_suffix != string::npos)
				{
					rkt_podid = tinfo->m_root.substr(prefix + FLY_PREFIX.size(), podid_suffix - prefix - FLY_PREFIX.size());
					auto appname_suffix = tinfo->m_root.find(FLY_APP_SUFFIX, podid_suffix+FLY_PODID_SUFFIX.size());
					if(appname_suffix != string::npos)
					{
						rkt_appname = tinfo->m_root.substr(podid_suffix + FLY_PODID_SUFFIX.size(),
														   appname_suffix-podid_suffix-FLY_PODID_SUFFIX.size());
						container_info.m_type = CT_RKT;
						container_info.m_id = rkt_podid + ":" + rkt_appname;
						container_info.m_name = rkt_appname;
						valid_id = true;
					}
				}
			}
		}
	}
	if(valid_id)
	{
		tinfo->m_container_id = container_info.m_id;

		unordered_map<string, sinsp_container_info>::const_iterator it = m_containers.find(container_info.m_id);
		if(it == m_containers.end())
		{
			switch(container_info.m_type)
			{
				case CT_DOCKER:
#ifndef _WIN32
					if(query_os_for_missing_info)
					{
						parse_docker(&container_info);
					}
#endif
					break;
				case CT_LXC:
					container_info.m_name = container_info.m_id;
					break;
				case CT_LIBVIRT_LXC:
					container_info.m_name = container_info.m_id;
					break;
				case CT_MESOS:
					container_info.m_name = container_info.m_id;
					break;
				case CT_RKT:
#ifndef _WIN32
					if(query_os_for_missing_info)
					{
						parse_rkt(&container_info, rkt_podid, rkt_appname);
					}
#endif
					break;
				default:
					ASSERT(false);
			}

			m_containers.insert(std::make_pair(container_info.m_id, container_info));
			if(container_to_sinsp_event(container_to_json(container_info), &m_inspector->m_meta_evt))
			{
				m_inspector->m_meta_evt_pending = true;
			}
		}
	}

	return valid_id;
}
Beispiel #3
0
bool sinsp_container_manager::resolve_container(sinsp_threadinfo* tinfo, bool query_os_for_missing_info)
{

	ASSERT(tinfo);
	bool valid_id = false;
	sinsp_container_info container_info;

	string rkt_podid, rkt_appname;
	// Start with cgroup based detection
	for(auto it = tinfo->m_cgroups.begin(); it != tinfo->m_cgroups.end(); ++it)
	{
		string cgroup = it->second;
		size_t pos;

		//
		// Non-systemd Docker
		//
		pos = cgroup.find_last_of("/");
		if(pos != string::npos)
		{
			if(cgroup.length() - pos - 1 == 64 &&
				cgroup.find_first_not_of("0123456789abcdefABCDEF", pos + 1) == string::npos)
			{
				container_info.m_type = CT_DOCKER;
				container_info.m_id = cgroup.substr(pos + 1, 12);
				valid_id = true;
				break;
			}
		}

		//
		// systemd Docker
		//
		pos = cgroup.find("docker-");
		if(pos != string::npos)
		{
			size_t pos2 = cgroup.find(".scope");
			if(pos2 != string::npos &&
				pos2 - pos - sizeof("docker-") + 1 == 64)
			{
				container_info.m_type = CT_DOCKER;
				container_info.m_id = cgroup.substr(pos + sizeof("docker-") - 1, 12);
				valid_id = true;
				break;
			}
		}

		//
		// Non-systemd libvirt-lxc
		//
		pos = cgroup.find(".libvirt-lxc");
		if(pos != string::npos &&
			pos == cgroup.length() - sizeof(".libvirt-lxc") + 1)
		{
			size_t pos2 = cgroup.find_last_of("/");
			if(pos2 != string::npos)
			{
				container_info.m_type = CT_LIBVIRT_LXC;
				container_info.m_id = cgroup.substr(pos2 + 1, pos - pos2 - 1);
				valid_id = true;
				break;
			}
		}

		//
		// systemd libvirt-lxc
		//
		pos = cgroup.find("-lxc\\x2");
		if(pos != string::npos)
		{
			size_t pos2 = cgroup.find(".scope");
			if(pos2 != string::npos &&
				pos2 == cgroup.length() - sizeof(".scope") + 1)
			{
				container_info.m_type = CT_LIBVIRT_LXC;
				container_info.m_id = cgroup.substr(pos + sizeof("-lxc\\x2"), pos2 - pos - sizeof("-lxc\\x2"));
				valid_id = true;
				break;
			}
		}

		//
		// Legacy libvirt-lxc
		//
		pos = cgroup.find("/libvirt/lxc/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_LIBVIRT_LXC;
			container_info.m_id = cgroup.substr(pos + sizeof("/libvirt/lxc/") - 1);
			valid_id = true;
			break;
		}

		//
		// Non-systemd LXC
		//
		pos = cgroup.find("/lxc/");
		if(pos != string::npos)
		{
			auto id_start = pos + sizeof("/lxc/") - 1;
			auto id_end = cgroup.find('/', id_start);
			container_info.m_type = CT_LXC;
			container_info.m_id = cgroup.substr(id_start, id_end - id_start);
			valid_id = true;
			break;
		}

		//
		// Mesos
		//
		pos = cgroup.find("/mesos/");
		if(pos != string::npos)
		{
			container_info.m_type = CT_MESOS;
			container_info.m_id = cgroup.substr(pos + sizeof("/mesos/") - 1);
			// Consider a mesos container valid only if we find the mesos_task_id
			// this will exclude from the container itself the mesos-executor
			// but makes sure that we have task_id parsed properly. Otherwise what happens
			// is that we'll create a mesos container struct without a mesos_task_id
			// and for all other processes we'll use it
			valid_id = set_mesos_task_id(&container_info, tinfo);
			break;
		}

		//
		// systemd rkt
		//
		// rkt cgroups
		// 1. /system.slice/k8s_d1efb75a-ad42-458e-af65-2b378f42173f.service/system.slice/redis.service
		// 2. /machine.slice/machine-rkt\x2dc508ad4c\x2d7fa4\x2d4513\x2d9d53\x2d007628003805.scope/system.slice/redis.service
		static const string COREOS_PODID_VAR = "container_uuid=";
		static const string SYSTEMD_UUID_ARG = "--uuid=";
		static const string SERVICE_SUFFIX = ".service";
		if(cgroup.rfind(SERVICE_SUFFIX) == cgroup.size() - SERVICE_SUFFIX.size())
		{
			// check if there is a parent with pod uuid var
			sinsp_threadinfo::visitor_func_t visitor = [&rkt_podid](sinsp_threadinfo* ptinfo)
			{
				for(const auto& env_var : ptinfo->get_env())
				{
					auto container_uuid_pos = env_var.find(COREOS_PODID_VAR);
					if(container_uuid_pos == 0)
					{
						rkt_podid = env_var.substr(COREOS_PODID_VAR.size());
						return false;
					}
				}
				for(const auto& arg : ptinfo->m_args)
				{
					if(arg.find(SYSTEMD_UUID_ARG) != string::npos)
					{
						rkt_podid = arg.substr(SYSTEMD_UUID_ARG.size());
						return false;
					}
				}
				return true;
			};
			tinfo->traverse_parent_state(visitor);

			if(!rkt_podid.empty())
			{
				auto last_slash = cgroup.find_last_of("/");
				rkt_appname = cgroup.substr(last_slash + 1, cgroup.size() - last_slash - SERVICE_SUFFIX.size() - 1);
				
				char image_manifest_path[SCAP_MAX_PATH_SIZE];
				snprintf(image_manifest_path, sizeof(image_manifest_path), "%s/var/lib/rkt/pods/run/%s/appsinfo/%s/manifest", scap_get_host_root(), rkt_podid.c_str(), rkt_appname.c_str());

				// First lookup if the container exists in our table, otherwise only if we are live check if it has
				// an entry in /var/lib/rkt. In capture mode only the former will be used.
				// In live mode former will be used only if we already hit that container
				if( m_containers.find(rkt_podid + ":" + rkt_appname) != m_containers.end() ||
					(query_os_for_missing_info && access(image_manifest_path, F_OK) == 0)
					)
				{
					container_info.m_type = CT_RKT;
					container_info.m_id = rkt_podid + ":" + rkt_appname;
					container_info.m_name = rkt_appname;
					valid_id = true;
					break;
				} 
			}
		}
	}

	// If anything has been found, try proc root based detection
	// right now used for rkt
	if(!valid_id)
	{
		// Try parsing from process root,
		// Strings used to detect rkt stage1-cores pods
		// TODO: detecting stage1-coreos rkt pods in this way is deprecated
		// we can remove it in the future
		static const string COREOS_PREFIX = "/opt/stage2/";
		static const string COREOS_APP_SUFFIX = "/rootfs";
		static const string COREOS_PODID_VAR = "container_uuid=";

		auto prefix = tinfo->m_root.find(COREOS_PREFIX);
		if(prefix == 0)
		{
			auto suffix = tinfo->m_root.find(COREOS_APP_SUFFIX, prefix);
			if(suffix != string::npos)
			{
				rkt_appname = tinfo->m_root.substr(prefix + COREOS_PREFIX.size(), suffix - prefix - COREOS_PREFIX.size());
				// It is a rkt pod with stage1-coreos

				sinsp_threadinfo::visitor_func_t visitor = [&rkt_podid, &container_info, &rkt_appname, &valid_id] (sinsp_threadinfo *ptinfo)
				{
					for(const auto& env_var : ptinfo->get_env())
					{
						auto container_uuid_pos = env_var.find(COREOS_PODID_VAR);
						if(container_uuid_pos == 0)
						{
							rkt_podid = env_var.substr(COREOS_PODID_VAR.size());
							container_info.m_type = CT_RKT;
							container_info.m_id = rkt_podid + ":" + rkt_appname;
							container_info.m_name = rkt_appname;
							valid_id = true;
							return false;
						}
					}
					return true;
				};

				// Try the current thread first. visitor returns true if no coreos pid
				// info was found. In this case we traverse the parents.
				if (visitor(tinfo))
				{
					tinfo->traverse_parent_state(visitor);
				}
			}
		}
		else
		{
			// String used to detect stage1-fly pods
			static const string FLY_PREFIX = "/var/lib/rkt/pods/run/";
			static const string FLY_PODID_SUFFIX = "/stage1/rootfs/opt/stage2/";
			static const string FLY_APP_SUFFIX = "/rootfs";

			auto prefix = tinfo->m_root.find(FLY_PREFIX);
			if(prefix == 0)
			{
				auto podid_suffix = tinfo->m_root.find(FLY_PODID_SUFFIX, prefix+FLY_PREFIX.size());
				if(podid_suffix != string::npos)
				{
					rkt_podid = tinfo->m_root.substr(prefix + FLY_PREFIX.size(), podid_suffix - prefix - FLY_PREFIX.size());
					auto appname_suffix = tinfo->m_root.find(FLY_APP_SUFFIX, podid_suffix+FLY_PODID_SUFFIX.size());
					if(appname_suffix != string::npos)
					{
						rkt_appname = tinfo->m_root.substr(podid_suffix + FLY_PODID_SUFFIX.size(),
														   appname_suffix-podid_suffix-FLY_PODID_SUFFIX.size());
						container_info.m_type = CT_RKT;
						container_info.m_id = rkt_podid + ":" + rkt_appname;
						container_info.m_name = rkt_appname;
						valid_id = true;
					}
				}
			}
		}
	}

	if(!valid_id) {
		tinfo->m_container_id = "";
	}
	else
	{
		tinfo->m_container_id = container_info.m_id;

		unordered_map<string, sinsp_container_info>::const_iterator it = m_containers.find(container_info.m_id);
		if(it == m_containers.end())
		{
			switch(container_info.m_type)
			{
				case CT_DOCKER:
#ifndef _WIN32
					if(query_os_for_missing_info)
					{
						parse_docker(&container_info);
					}
#endif
					break;
				case CT_LXC:
					container_info.m_name = container_info.m_id;
					break;
				case CT_LIBVIRT_LXC:
					container_info.m_name = container_info.m_id;
					break;
				case CT_MESOS:
					container_info.m_name = container_info.m_id;
					break;
				case CT_RKT:
#ifndef _WIN32
					if(query_os_for_missing_info)
					{
						parse_rkt(&container_info, rkt_podid, rkt_appname);
					}
#endif
					break;
				default:
					ASSERT(false);
			}

			add_container(container_info);
			if(container_to_sinsp_event(container_to_json(container_info), &m_inspector->m_meta_evt))
			{
				m_inspector->m_meta_evt_pending = true;
			}
		}
	}

	return valid_id;
}