《Clair二次开发指南2——analyze-local-images源码剖析》

我们先分析下analyze-local-images这个客户端,然后在下一篇文章中在分析Clair。这样我们可以很清楚的了解到,analyze-local-images向Clair发送了什么数据。

首先analyze-local-images定义了几个全局变量。代码如下。

const (
	postLayerURI        = "/v1/layers"
	getLayerFeaturesURI = "/v1/layers/%s?vulnerabilities"
	httpPort            = 9279
)

var (
	flagEndpoint        = flag.String("endpoint", "http://127.0.0.1:6060", "Address to Clair API")
	flagMyAddress       = flag.String("my-address", "127.0.0.1", "Address from the point of view of Clair")
	flagMinimumSeverity = flag.String("minimum-severity", "Negligible", "Minimum severity of vulnerabilities to show (Unknown, Negligible, Low, Medium, High, Critical, Defcon1)")
	flagColorMode       = flag.String("color", "auto", "Colorize the output (always, auto, never)")
)


在使用analyze-local-images时,我们可以指定一些参数。

analyze-local-images -endpoint "http://10.28.182.152:6060" -my-address "10.28.182.151" nginx:latest

其中,endpoint为clair主机的ip地址。my-address为运行 analyze-local-images这个客户端的地址。

postLayerURI是向clair API V1发送数据库的路由,getLayerFeaturesURI是从clair API V1获取漏洞信息的路由。


analyze-local-images在主函数调用intMain()函数,而intMain会首先去解析用户的输入参数。例如刚才的endpoint。

func intMain() int {  
    //解析命令行参数,并给刚才定义的一些全局变量赋值。  
    ......  
        //创建一个临时目录  
    tmpPath, err := ioutil.TempDir("", "analyze-local-image-")  
    //在/tmp目录下创建以analyze-local-image-开头的文件夹。  
 //为了能够清楚的观察/tmp下目录的变化,我们将defer os.RemoveAll(tmpPath)这句注释掉,再重新编译。  
  
    ......  
    //调用AnalyzeLocalImage方法分析镜像  
    go func() {  
   analyzeCh <- AnalyzeLocalImage(imageName, minSeverity, *flagEndpoint, *flagMyAddress, tmpPath)  
    }()  
}  


程序执行流程是main()->intMain()->AnalyzeLocalImage()。现在我们跟进入AnalyzeLocalImage()

镜像被解压到tmp目录下的目录结构如下。

func AnalyzeLocalImage(imageName string, minSeverity database.Severity, endpoint, myAddress, tmpPath string) error {  
    //保存镜像到tmp目录下  
    //调用save方法  
    //save方法的原理就是使用docker save 镜像名先将镜像打包成tar文件  
    //然后使用tar命令将文件再解压到tmp文件中。  
    err := save(imageName, tmpPath)  
    .......  
    //调用historyFromManifest方法,读取manifest.json文件获取每一层的id名,保存在layerIDs中。  
    //如果从manifest.json文件中获取不到,则读取历史记录  
      
    layerIDs, err := historyFromManifest(tmpPath)  
    if err != nil {  
    layerIDs, err = historyFromCommand(imageName)  
    }  
    ......  
    //如果clair不在本机,则在analyze-local-images上开启HTTP服务,默认端口为9279  
    ......  
    //分析每一层,既将每一层下的layer.tar文件发送到clair服务端  
    err = analyzeLayer(endpoint, tmpPath+"/"+layerIDs[i]+"/layer.tar", layerIDs[i], layerIDs[i-1])  
  
    ......  
}  
 

到这里,程序的执行流程是main()->intMain()->AnalyzeLocalImage()—>analyzeLayer()->getLayer()

func AnalyzeLocalImage(imageName string, minSeverity database.Severity, endpoint, myAddress, tmpPath string) error {

    ......

    //获取漏洞信息
	layer, err := getLayer(endpoint, layerIDs[len(layerIDs)-1])
	//打印漏洞报告
    ......
	for _, feature := range layer.Features {
		if len(feature.Vulnerabilities) > 0 {
			for _, vulnerability := range feature.Vulnerabilities {
				severity := database.Severity(vulnerability.Severity)
				isSafe = false

				if minSeverity.Compare(severity) > 0 {
					continue
				}

				hasVisibleVulnerabilities = true
				vulnerabilities = append(vulnerabilities, vulnerabilityInfo{vulnerability, feature, severity})
			}
		}
	}
	//排序输出报告美化
	.....

}


通过源码分析可知,与clair后端进行交换的两个主要方法为analyzeLayer和getLayer。analyzeLayer向clair发送JSON格式的数据。而getLayer用来获取clair的请求。并将json格式数据解码后格式化输出。


至此,对analyze-local-images的源码已经分析完毕。从中可以可以看出。analyze-local-images做的事情很简单。

就是将layer.tar发送给clair。并将clair分析后的结果通过API接口获取到并在本地打印。那么下一篇文章,我们就深入剖析下clair的源码。

相关文章
相关标签/搜索