@@ -16,6 +16,7 @@ package osinfo
1616import  (
1717	"bufio" 
1818	"bytes" 
19+ 	"context" 
1920	"fmt" 
2021	"io/ioutil" 
2122	"regexp" 
@@ -29,94 +30,167 @@ var (
2930	entRelVerRgx  =  regexp .MustCompile (`\d+(\.\d+)?(\.\d+)?` )
3031)
3132
32- const  (
33- 	osRelease  =  "/etc/os-release" 
34- 	oRelease   =  "/etc/oracle-release" 
35- 	rhRelease  =  "/etc/redhat-release" 
33+ var  _  Provider  =  & LinuxOsInfoProvider {}
34+ 
35+ var  (
36+ 	defaultReleaseFilepath  =  "/etc/os-release" 
37+ 	oracleReleaseFilepath   =  "/etc/oracle-release" 
38+ 	redHatReleaseFilepath   =  "/etc/redhat-release" 
3639)
3740
38- func  parseOsRelease (releaseDetails  string ) * OSInfo  {
39- 	oi  :=  & OSInfo {}
41+ // Get reports OSInfo. 
42+ func  Get () (* OSInfo , error ) {
43+ 	// Eventually we will get rid of this function and will use providers directly 
44+ 	// Providers should support context to be able to handle cancelation and logging 
45+ 	// so far we just create empty context to connect the API. 
46+ 	ctx  :=  context .TODO ()
47+ 
48+ 	osInfoProvider , err  :=  NewLinuxOsInfoProvider (getOsNameAndVersionProvider (ctx ))
49+ 	if  err  !=  nil  {
50+ 		return  nil , fmt .Errorf ("unable to extract osinfo, err:  %w" , err )
51+ 	}
52+ 
53+ 	osInfo , err  :=  osInfoProvider .Get (ctx )
54+ 	if  err  !=  nil  {
55+ 		return  & osInfo , err 
56+ 	}
57+ 
58+ 	return  & osInfo , nil 
59+ }
60+ 
61+ // LinuxOsInfoProvider is a provider of OSInfo for the linux based systems. 
62+ type  LinuxOsInfoProvider  struct  {
63+ 	nameAndVersionProvider  osNameAndVersionProvider 
64+ 	uts                     unix.Utsname 
65+ }
66+ 
67+ // NewLinuxOsInfoProvider is a constructor function for LinuxOsInfoProvider. 
68+ func  NewLinuxOsInfoProvider (nameAndVersionProvider  osNameAndVersionProvider ) (* LinuxOsInfoProvider , error ) {
69+ 	var  uts  unix.Utsname 
70+ 	if  err  :=  unix .Uname (& uts ); err  !=  nil  {
71+ 		return  nil , fmt .Errorf ("unable to get unix.Uname, err: %w" , err )
72+ 	}
73+ 
74+ 	return  & LinuxOsInfoProvider {
75+ 		nameAndVersionProvider : nameAndVersionProvider ,
76+ 		uts :                    uts ,
77+ 	}, nil 
78+ }
79+ 
80+ // Get gather all required information and returns OSInfo. 
81+ func  (oip  * LinuxOsInfoProvider ) Get (ctx  context.Context ) (OSInfo , error ) {
82+ 	short , long , version  :=  oip .nameAndVersionProvider ()
83+ 
84+ 	return  OSInfo {
85+ 		ShortName : short ,
86+ 		LongName :  long ,
87+ 		Version :   version ,
88+ 
89+ 		Hostname :      oip .hostName (),
90+ 		Architecture :  oip .architecture (),
91+ 		KernelRelease : oip .kernelRelease (),
92+ 		KernelVersion : oip .kernelVersion (),
93+ 	}, nil 
94+ }
95+ 
96+ func  (oip  * LinuxOsInfoProvider ) hostName () string  {
97+ 	return  stringFromUtsField (oip .uts .Nodename )
98+ }
99+ 
100+ func  (oip  * LinuxOsInfoProvider ) architecture () string  {
101+ 	return  NormalizeArchitecture (stringFromUtsField (oip .uts .Machine ))
102+ }
103+ func  (oip  * LinuxOsInfoProvider ) kernelRelease () string  {
104+ 	return  stringFromUtsField (oip .uts .Release )
105+ }
106+ 
107+ func  (oip  * LinuxOsInfoProvider ) kernelVersion () string  {
108+ 	return  stringFromUtsField (oip .uts .Version )
109+ }
110+ 
111+ func  stringFromUtsField (field  [65 ]byte ) string  {
112+ 	// unix.Utsname Fields are [65]byte so we need to trim any trailing null characters. 
113+ 	return  string (bytes .TrimRight (field [:], "\x00 " ))
114+ }
115+ 
116+ func  getOsNameAndVersionProvider (_  context.Context ) osNameAndVersionProvider  {
117+ 	return  func () (string , string , string ) {
118+ 		var  (
119+ 			extractNameAndVersion  func (string ) (string , string , string )
120+ 			releaseFile            string 
121+ 		)
122+ 
123+ 		defaultShortName , defaultLongName , defaultVersion  :=  DefaultShortNameLinux , "" , "" 
124+ 
125+ 		switch  {
126+ 		// Check for /etc/os-release first. 
127+ 		case  util .Exists (defaultReleaseFilepath ):
128+ 			releaseFile  =  defaultReleaseFilepath 
129+ 			extractNameAndVersion  =  parseOsRelease 
130+ 		case  util .Exists (oracleReleaseFilepath ):
131+ 			releaseFile  =  oracleReleaseFilepath 
132+ 			extractNameAndVersion  =  parseEnterpriseRelease 
133+ 		case  util .Exists (redHatReleaseFilepath ):
134+ 			releaseFile  =  redHatReleaseFilepath 
135+ 			extractNameAndVersion  =  parseEnterpriseRelease 
136+ 		default :
137+ 			return  defaultShortName , defaultLongName , defaultVersion 
138+ 		}
139+ 
140+ 		b , err  :=  ioutil .ReadFile (releaseFile )
141+ 		if  err  !=  nil  {
142+ 			// TODO: log an error 
143+ 			return  defaultShortName , defaultLongName , defaultVersion 
144+ 		}
145+ 
146+ 		return  extractNameAndVersion (string (b ))
147+ 	}
148+ }
149+ 
150+ func  parseOsRelease (releaseDetails  string ) (shortName , longName , version  string ) {
151+ 	scanner  :=  bufio .NewScanner (strings .NewReader (releaseDetails ))
40152
41- 	scanner  :=  bufio .NewScanner (bytes .NewReader ([]byte (releaseDetails )))
42153	for  scanner .Scan () {
43154		entry  :=  strings .Split (scanner .Text (), "=" )
44155		switch  entry [0 ] {
45156		case  "" :
46157			continue 
47158		case  "PRETTY_NAME" :
48- 			oi . LongName  =  strings .Trim (entry [1 ], `"` )
159+ 			longName  =  strings .Trim (entry [1 ], `"` )
49160		case  "VERSION_ID" :
50- 			oi . Version  =  strings .Trim (entry [1 ], `"` )
161+ 			version  =  strings .Trim (entry [1 ], `"` )
51162		case  "ID" :
52- 			oi . ShortName  =  strings .Trim (entry [1 ], `"` )
163+ 			shortName  =  strings .Trim (entry [1 ], `"` )
53164		}
54- 		if  oi .LongName  !=  ""  &&  oi .Version  !=  ""  &&  oi .ShortName  !=  ""  {
165+ 
166+ 		// TODO: Replace with binary mask 
167+ 		if  longName  !=  ""  &&  version  !=  ""  &&  shortName  !=  ""  {
55168			break 
56169		}
57170	}
58171
59- 	if  oi . ShortName  ==  ""  {
60- 		oi . ShortName  =  Linux 
172+ 	if  shortName  ==  ""  {
173+ 		shortName  =  DefaultShortNameLinux 
61174	}
62175
63- 	return  oi 
176+ 	return  shortName ,  longName ,  version 
64177}
65178
66- func  parseEnterpriseRelease (releaseDetails  string ) * OSInfo  {
67- 	rel   :=   releaseDetails 
179+ func  parseEnterpriseRelease (releaseDetails  string ) ( shortName   string ,  longName   string ,  version   string )  {
180+ 	shortName   =   DefaultShortNameLinux 
68181
69- 	var  sn  string 
70182	switch  {
71- 	case  strings .Contains (rel , "CentOS" ):
72- 		sn  =  "centos" 
73- 	case  strings .Contains (rel , "Red Hat" ):
74- 		sn  =  "rhel" 
75- 	case  strings .Contains (rel , "Oracle" ):
76- 		sn  =  "ol" 
183+ 	case  strings .Contains (releaseDetails , "CentOS" ):
184+ 		shortName  =  "centos" 
185+ 	case  strings .Contains (releaseDetails , "Red Hat" ):
186+ 		shortName  =  "rhel" 
187+ 	case  strings .Contains (releaseDetails , "Oracle" ):
188+ 		shortName  =  "ol" 
77189	}
78190
79- 	return  & OSInfo {
80- 		ShortName : sn ,
81- 		LongName :  strings .Replace (rel , " release " , " " , 1 ),
82- 		Version :   entRelVerRgx .FindString (rel ),
83- 	}
84- }
85- 
86- // Get reports OSInfo. 
87- func  Get () (* OSInfo , error ) {
88- 	var  oi  * OSInfo 
89- 	var  parseReleaseFunc  func (string ) * OSInfo 
90- 	var  releaseFile  string 
91- 	switch  {
92- 	// Check for /etc/os-release first. 
93- 	case  util .Exists (osRelease ):
94- 		releaseFile  =  osRelease 
95- 		parseReleaseFunc  =  parseOsRelease 
96- 	case  util .Exists (oRelease ):
97- 		releaseFile  =  oRelease 
98- 		parseReleaseFunc  =  parseEnterpriseRelease 
99- 	case  util .Exists (rhRelease ):
100- 		releaseFile  =  rhRelease 
101- 		parseReleaseFunc  =  parseEnterpriseRelease 
102- 	}
191+ 	longName  =  strings .Replace (releaseDetails , " release " , " " , 1 )
103192
104- 	b , err  :=  ioutil .ReadFile (releaseFile )
105- 	if  err  !=  nil  {
106- 		oi  =  & OSInfo {ShortName : Linux }
107- 	} else  {
108- 		oi  =  parseReleaseFunc (string (b ))
109- 	}
110- 
111- 	var  uts  unix.Utsname 
112- 	if  err  :=  unix .Uname (& uts ); err  !=  nil  {
113- 		return  oi , fmt .Errorf ("unix.Uname error: %v" , err )
114- 	}
115- 	// unix.Utsname Fields are [65]byte so we need to trim any trailing null characters. 
116- 	oi .Hostname  =  string (bytes .TrimRight (uts .Nodename [:], "\x00 " ))
117- 	oi .Architecture  =  Architecture (string (bytes .TrimRight (uts .Machine [:], "\x00 " )))
118- 	oi .KernelVersion  =  string (bytes .TrimRight (uts .Version [:], "\x00 " ))
119- 	oi .KernelRelease  =  string (bytes .TrimRight (uts .Release [:], "\x00 " ))
193+ 	version  =  entRelVerRgx .FindString (releaseDetails )
120194
121- 	return  oi ,  nil 
195+ 	return  shortName ,  longName ,  version 
122196}
0 commit comments