登录时显示服务器信息

/etc/motd 里可以设置登录 Linux 服务器时显示的信息,但是只能显示静态信息,如果需要动态信息,可以通过 /etc/profile.d/ 下的脚本来实现。本文记录一种通过脚本调用 CMDB 接口获取服务器的业务,机房,状态以及联系人信息,在登录时显示的方法。效果如下图。

Linux登录时显示服务器信息

CMDB接口规格

为简化 Shell 脚本的调用,CMDB 接口直接输出显示结果, 即带颜色的服务器信息。以下是基于 iTop CMDB 的实现实例。

<?php
/**
 * Usage:
 * File Name: logininfo.php
 * Author: annhe  
 * Created Time: 2017-03-29 10:05:48
 * 用于登录机器时打印机器信息
 * 机器上部署计划任务访问此接口
 **/

require 'common/init.php';

define('HEAD',"\n##################### Server Info ######################\n");
define('WARN',"WARNING!!此机器未登记业务信息,有被下线风险");
define('TIP',"如果您认为以上信息有误,请及时联系运维修正错误");
define('TAIL',"\n########################################################\n");

function red($text) {
	return "\033[31m     $text \033[0m";
}

function blink($text) {
	return "\033[5;33m     $text \033[0m";
}

function skyblue($text) {
	return "\033[36m     $text \033[0m";
}

function yellow($text) {
	return "\033[33m     $text \033[0m";
}

function white($text) {
	return "\033[37m     $text \033[0m";
}

function errorInfo() {
	$info = HEAD . skyblue("获取业务信息失败,请联系运维") .  TAIL;
	return $info;
}

function getApps($relations) {
	$apps = [];
	foreach($relations as $k => $v) {
		if(preg_match("/^Server::.*/", $k)) {
			foreach($v as $key => $val) {
				if(preg_match('/^ApplicationSolution::.*/', $val['key'])) {
					$item = explode('::', $val['key'])[2];
					$item = explode('.', $item)[1];
					$apps[] = $item;
				}
			}
		}
	}
	return $apps;
}

function getServerLoginInfo($ip)
{
	global $iTopAPI;
	$query = "SELECT Server AS s JOIN PhysicalIP AS ip ON ip.connectableci_id=s.id WHERE ip.ipaddress = '$ip'";	

	$optional = array(
		'output_fields' => array("Server"=>"status,location_name","ApplicationSolution"=>"name"),
		'show_relations' => ["Server","ApplicationSolution","Location","Person"],
		'hide_relations' => [],
		'direction' => 'both',
		'filter' => ["Server","ApplicationSolution","Person"],
		'depth' => 2,
	);
	$data = $iTopAPI->extRelated("Server", $query, "impacts", $optional);

	$data = json_decode($data, true);
	$obj = $data['objects'];
	if(!$obj)
	{
		return(errorInfo());
	}
	
	$relations = $data['relations'];
	$apps = getApps($relations);
	$contacts = [];
	$location = "";
	$status = "";
	$map_status=array("production"=>"使用中","stock"=>"库存(此状态随时可能被下线)",
		"obsolete"=>"废弃(此状态随时可能被重装或关机)","implementation"=>"上线中");
	foreach($obj as $k => $v) {
		if($v['class'] == "Person") {
			$contacts[] = $v['fields']['friendlyname'];
		}
		if($v['class'] == "Server") {
			$location = $v['fields']['location_name'];
			$status = $map_status[$v['fields']['status']];
		}
	}

	if(!$apps) {
		$apps = blink("业  务:" . WARN);
	} else {
		$apps = implode(",", $apps);
		$apps = red("业  务:" . $apps);
	}
	$contacts = implode(",", $contacts);
	$info = HEAD;
	$info .= $apps . "\n";
	$info .= skyblue("机  房:" . $location) . "\n";
	$info .= skyblue("状  态:" . $status) . "\n";
	$info .= white("联系人:" . $contacts) . "\n";
	$info .= "\n" . yellow(TIP) . TAIL;
	return($info);
}


if(isset($_GET['ip'])) {
	$ip = $_GET['ip'];
	$key = "logininfo_" . $ip;

	if(isset($_GET['cache']) && $_GET['cache'] == "set")
	{
		$ret = getServerLoginInfo($ip);
		die(setCache($key, $ret));
	}

	if(isset($_GET['cache']) && $_GET['cache'] == "false")
	{
		die(getServerLoginInfo($ip));
	}else
	{
		// 首先获取缓存内容
		$ret = getCache($key);
		if(!$ret)
		{
			$ret = getServerLoginInfo($ip);
			setCache($key, $ret);
		}
		die($ret);
	}
}else
{
	die(errorInfo());
}

计划任务脚本

考虑到登录时才调用 CMDB,可能会有延迟,导致用户体验差,所以通过计划任务定时将获取信息,存储到 /etc/logininfo.conf 中,/etc/profile.d 下的脚本直接输出 logininfo.conf 即可。计划任务脚本如下:

#!/bin/bash

# crontab需要设置PATH
export PATH=$PATH:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

infoFile="/etc/logininfo.conf"
tmpFile="/tmp/logininfo.conf"

# 随机等待一段时间,防止cmdbapi请求量过大
if [ $# -lt 1 ];then
	waitS=$[1]RANDOM%300
	sleep $waitS
fi

# 登录时显示机器业务信息
IP=`ip add |grep -E "inet 10\." |grep -v "/32" |awk '{print $2}' |cut -f1 -d'/' |head -n 1`
curl --connect-timeout 2 -s "http://cmdb.xxx.com/api/logininfo.php?ip=$IP" >$tmpFile

grep "# Server Info #" $tmpFile &>/dev/null && cat $tmpFile > $infoFile

但是这种方法会频繁调用 CMDB 接口,如果服务器量级较大,可能会对 CMDB 造成一定压力,CMDB 端应加缓存来优化性能。

profile脚本

然后在 /etc/profile.d/ 下新建一个文件 info.sh

# 登录时显示机器业务信息
user=`who am i |awk '{print $1}'`
userSu=`whoami`
# 通过su sudo切换后,user和userSu变量将不同,此时不显示登录信息
if [ "$user"x == "$userSu"x ];then
	cat /etc/logininfo.conf
fi

(全文完)

参考资料

参考资料
1 RANDOM%300

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注