Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

"""Logrotate module.""" 

import json 

import os 

import re 

 

from charmhelpers.core import hookenv 

 

LOGROTATE_DIR = "/etc/logrotate.d/" 

JUJU_LOGROTATE_FILE = "/etc/logrotate.d/juju-common" 

 

 

class LogrotateHelper: 

"""Helper class for logrotate charm.""" 

 

def __init__(self): 

"""Init function.""" 

self.retention = hookenv.config('logrotate-retention') 

self.logfiles_custom = hookenv.config('logfiles-custom') 

 

def read_config(self): 

"""Read changes from disk. 

 

Config changed/install hooks dumps config out to disk, 

Here we read that config to update the cronjob 

""" 

config_file = open("/etc/logrotate_cronjob_config", "r") 

lines = config_file.read() 

lines = lines.split('\n') 

 

self.retention = int(lines[2]) 

 

def modify_configs(self): 

"""Modify the logrotate config files.""" 

for config_file in os.listdir(LOGROTATE_DIR): 

file_path = LOGROTATE_DIR + config_file 

 

logrotate_file = open(file_path, 'r') 

content = logrotate_file.read() 

logrotate_file.close() 

 

mod_contents = self.modify_content(content) 

 

mod_contents = self.modify_header(mod_contents) 

 

logrotate_file = open(file_path, 'w') 

logrotate_file.write(mod_contents) 

logrotate_file.close() 

 

# Remove the juju-common file and re-add it with fresh configurations 

self.cleanup_custom_config() 

# Add the custom configs here 

self.write_custom_config() 

 

@classmethod 

def split_items(cls, content): 

"""Split the contents in a logrotate file in separate entries. 

 

If multiple are found in the file) and put in a list for further 

processing 

""" 

split = content.split('\n') 

items = [] 

string = "" 

for row in split: 

string += row + '\n' 

if '}' in row: 

items.append(string) 

string = "" 

continue 

return items 

 

def modify_content(self, content): 

"""Edit the content of a logrotate file.""" 

items = self.split_items(content) 

 

# Work on each item - checking the rotation configuration and setting 

# the rotate option to the appropriate value 

results = [] 

for item in items: 

count = self.calculate_count(item, self.retention) 

rotate = 'rotate {}'.format(count) 

# if rotate is missing, add it as last line in the item entry 

if 'rotate' in item: 

result = re.sub(r'rotate \d+\.?[0-9]*', rotate, item) 

else: 

result = item.replace('}', rotate + '\n}') 

results.append(result) 

 

results = '\n'.join(results) 

 

return results 

 

def modify_header(self, content): 

"""Add Juju headers to the file.""" 

header = "# Configuration file maintained by Juju. Local changes may be overwritten" 

 

split = content.split('\n') 

if split[0].startswith(header): 

result = content 

else: 

result = header + '\n' + content 

 

return result 

 

@classmethod 

def calculate_count(cls, item, retention): 

"""Calculate rotate based on rotation interval. Always round up.""" 

# Fallback to default lowest retention - days 

# better to keep the logs than lose them 

count = retention 

# Daily 1:1 to configuration retention period (in days) 

if 'daily' in item: 

count = retention 

# Weekly rounding up, as weeks are 7 days 

if 'weekly' in item: 

count = int(round(retention/7)) 

# Monthly default 30 days and round up because of 28/31 days months 

if 'monthly' in item: 

count = int(round(retention/30)) 

# For every 360 days - add 1 year 

if 'yearly' in item: 

count = retention // 360 + 1 if retention > 360 else 1 

 

return count 

 

@classmethod 

def generate_custom_configurations(cls, custom_data): 

"""Apply custom logrotate configurations.""" 

try: 

objects = json.loads(custom_data) 

except ValueError: 

hookenv.log('Custom JSON object could not be decoded.', 

level='ERROR') 

hookenv.status_set('error', 'Invalid syntax for custom JSON \ 

logfiles object.') 

return "" 

items = "" 

for obj in objects: 

items += obj['path'] + " {\n" 

for option in obj['options']: 

items += " " + option + "\n" 

items += "}\n" 

 

return items 

 

def cleanup_custom_config(self): 

"""Cleanup juju-common logrotate file.""" 

if os.path.exists(JUJU_LOGROTATE_FILE): 

os.remove(JUJU_LOGROTATE_FILE) 

 

def write_custom_config(self): 

"""Write the juju-common logrotate file.""" 

custom = self.generate_custom_configurations(self.logfiles_custom) 

custom = self.modify_header(custom) 

logrotate_file = open(JUJU_LOGROTATE_FILE, 'w') 

logrotate_file.write(custom) 

logrotate_file.close()