Compare commits
13 Commits
read-file-
...
master
Author | SHA1 | Date |
---|---|---|
Mike Holloway | 0cd721909b | 3 years ago |
Mike Holloway | 315aa55ab7 | 3 years ago |
Mike Holloway | 4d180a1212 | 3 years ago |
Mike Holloway | 3c420dc3db | 3 years ago |
Mike Holloway | 54b52273da | 3 years ago |
Mike Holloway | 93fd6f916b | 3 years ago |
Mike Holloway | 8e2f4e3db8 | 3 years ago |
Mike Holloway | bb77957ed4 | 3 years ago |
Mike Holloway | a46c855960 | 3 years ago |
Mike Holloway | 0ea14fd132 | 3 years ago |
Mike Holloway | 7020adee58 | 3 years ago |
Mike Holloway | 399459c744 | 3 years ago |
Mike Holloway | b4b01a5cf4 | 3 years ago |
5 changed files with 220 additions and 0 deletions
@ -1 +1,2 @@ |
||||
.*.sw* |
||||
main |
||||
|
@ -0,0 +1,55 @@ |
||||
## Level 1 Questions |
||||
1. How would you prove the code is correct? |
||||
|
||||
To prove the code is correct I suppose I could set up a test environment |
||||
where I could account for all connections and run tests like |
||||
ssh connections, dhclient or dig (dns) connections, nmap port |
||||
scans, and then ensure the connections I expect from the tests |
||||
appear in the program's output. |
||||
|
||||
2. How would you make this solution better? |
||||
|
||||
I'd improve the solution by making the functions more focused on |
||||
specific tasks, improving how I present the interface of each |
||||
function to each other to more specifically eliminate type |
||||
or value errors. I'd also allot more time to complete the task |
||||
since I wasn't able to find enough before the deadline. |
||||
3. Is it possible for this program to miss a connection? |
||||
|
||||
Yes, if the connection is brief enough so as not to last more than 10 |
||||
seconds and thereby be missed by the most recent read of the |
||||
/proc/net/tcp file |
||||
4. If you weren't following these requirements, how would you solve the problem of logging every new connection? |
||||
|
||||
I would likely find a solution that leverages inotify to detect any change to the file and then read it, |
||||
rather than polling it every 10 seconds. |
||||
|
||||
## Level 2 Questions |
||||
1. Why did you choose 'x' to write the build automation? |
||||
|
||||
I would simply choose bash, as it's what I'm most familiar with and it |
||||
can reliably use the go build tools as well as invoke testing |
||||
systems like kvm/qemu, docker/podman and the like. |
||||
2. Is there anything else you would test if you had more time? |
||||
|
||||
If I had more time I'd spend it fleshing out my testing as outlined above |
||||
and doing a more thorough job of structuring my data in the way |
||||
that I've modeled it in my head - the choice of go definitely |
||||
consigned me to reading more than writing with the little time |
||||
I had. Should have gone with bash I think. |
||||
3. What is the most important tool, script, or technique you have for solving |
||||
problems in production? Explain why this tool/script/technique is the most important. |
||||
|
||||
|
||||
## Level 3 Questions |
||||
|
||||
1. If you had to deploy this program to hundreds of servers, what would be your |
||||
preferred method and why? |
||||
|
||||
I would use ansible and use git to clone, build, and install the script. |
||||
This method is my preferred one because it's simple to |
||||
troubleshoot in the event that I run into issues and |
||||
ansible doesn't require a central orchestrator node. It's |
||||
also the Infrastructure-as-code tool I'm most familiar with. |
||||
2. What is the hardest technical problem or outage you've had to solve in your |
||||
career? Explain what made it so difficult? |
@ -0,0 +1,24 @@ |
||||
# teleport_devops_challenge |
||||
|
||||
WARNING: This program is in an incomplete state and does not build successfully. |
||||
The latest commit that builds successfully can be found here: |
||||
https://git.libre.audio/seasharp/teleport_devops_challenge/commit/93fd6f916bc5a6b7504c5475f7cbcebabaae5277 |
||||
|
||||
|
||||
## Dependencies |
||||
|
||||
- golang 'encoding' package |
||||
|
||||
## Building |
||||
|
||||
Ensure your $GOPATH is set correctly and run: |
||||
|
||||
1. Execute `go build main.go` in repository root |
||||
2. Execute `go install teleport_devops_challenge` |
||||
|
||||
## Executing |
||||
|
||||
Ensure GOPATH/bin (GOPATH = `go env GOPATH`) has been added to your shell $PATH |
||||
or execute the following: |
||||
|
||||
`PATH=/home/$(whoami)/go/bin:$PATH teleport_devops_challenge` |
@ -0,0 +1,105 @@ |
||||
package main |
||||
|
||||
import ( |
||||
"reflect" |
||||
//"./timer"
|
||||
"time" |
||||
"fmt" |
||||
"strings" |
||||
"regexp" |
||||
"io/ioutil" |
||||
"encoding/hex" |
||||
) |
||||
|
||||
|
||||
var tcp_data string = read_tcp_file("/proc/net/tcp") |
||||
|
||||
func main() { |
||||
var loops int = 0 |
||||
// How to split on space-delimited fields, then colon-delimited fields?
|
||||
// How to turn this byte into a string?
|
||||
|
||||
// /proc/net/tcp hex addresses need to be reversed two-character-wise
|
||||
// and then converted byte by byte (2 char at a time)
|
||||
//fmt.Println(convert_address(reverse_string(reverse_bytes("0100007F"))))
|
||||
|
||||
for _ = range time.Tick(10 * time.Second) { |
||||
fmt.Println("Waiting 10 seconds...") |
||||
for num, row := range get_tcp_rows(tcp_data) { |
||||
row_type := reflect.TypeOf(row) |
||||
fmt.Println(num, " ", row_type) |
||||
} |
||||
// if loops modulo 6 (1min) then
|
||||
// for address in address_list do
|
||||
// if (grep address address_list | wc -l >=3) then
|
||||
// This is a port scan!
|
||||
// fi
|
||||
// done
|
||||
// elseif (wc -l old_tcp_file < wc -l tcp_file) then
|
||||
// for i in (wc -l tcp_file - wc -l old_tcp_flle) do
|
||||
// print New Connection! reverse_strng(reverse_bytes(tcp_file[i])) // This oversimplifies row value selection for the sake
|
||||
// // of pseudocode
|
||||
// done
|
||||
// else
|
||||
// "No new connections. Waiting another 10 seconds..."
|
||||
// fi
|
||||
loops++ |
||||
} |
||||
} |
||||
|
||||
func check(e error) { |
||||
if e != nil { |
||||
panic(e) |
||||
} |
||||
} |
||||
|
||||
// Aiming for an array of [string]string maps
|
||||
// Am I looking for a map[string]interface here?
|
||||
func get_tcp_rows(connections_file string) []string { |
||||
tcp_lines := strings.Split(connections_file, "\n") |
||||
regexpression := regexp.MustCompile(`[\r\n\t\f\v]+`) |
||||
tcp_columns := regexpression.Split(tcp_lines[0], -1) |
||||
var tcp_values map[string]string |
||||
|
||||
for i, line := range tcp_lines[1:] { |
||||
trim_line := strings.TrimSpace(line) |
||||
values := regexpression.Split(trim_line, -1) |
||||
column := tcp_columns[i] |
||||
tcp_values[column] = values |
||||
} |
||||
return tcp_values |
||||
} |
||||
|
||||
// Take a string, create a rune slice, and use a loop to reverse it character-wise.
|
||||
func reverse_bytes(s string) string { |
||||
runes := []rune(s) |
||||
for i, j := len(runes)-2, len(runes)-1; j > 0; i, j = i-2, j-2 { |
||||
runes[i], runes[j] = runes[j], runes[i] |
||||
} |
||||
return string(runes) |
||||
} |
||||
|
||||
func reverse_string(s string) string { |
||||
runes := []rune(s) |
||||
for i, j := 0, len(runes)-1; i < j; i, j = i+1, j-1 { |
||||
runes[i], runes[j] = runes[j], runes[i] |
||||
} |
||||
return string(runes) |
||||
} |
||||
// Store data function
|
||||
// Loads all fields and subfields into storage (memory? where?)
|
||||
// State check function
|
||||
// hash each line, use to determine new lines, convert to readable, and print
|
||||
|
||||
|
||||
func convert_address(address string) []byte { |
||||
output, err := hex.DecodeString(address) |
||||
check(err) |
||||
return output |
||||
} |
||||
func read_tcp_file(connections_file_path string) string { |
||||
data, err := ioutil.ReadFile(connections_file_path) |
||||
check(err) |
||||
fmt.Println("Data file read successfully.\n") |
||||
return string(data) |
||||
} |
@ -0,0 +1,35 @@ |
||||
package timer |
||||
|
||||
import ( |
||||
"fmt" |
||||
"time" |
||||
//"reflect"
|
||||
) |
||||
|
||||
func New(duration_int int, unit string) *time.Timer { |
||||
|
||||
start := time.NewTimer(0) |
||||
duration := time.Duration(duration_int) |
||||
// fmt.Println(reflect.TypeOf(duration))
|
||||
// timer_10s := time.NewTimer(10 * time.Second)
|
||||
// timer_1m := time.NewTimer(1 * time.Minute)
|
||||
fmt.Println("Duration: ", duration_int, "Unit: ", unit, ".") |
||||
if unit == "Second" { |
||||
start = time.NewTimer(duration * time.Second) |
||||
} else if unit == "Minute" { |
||||
start = time.NewTimer(duration * time.Minute) |
||||
} else { |
||||
fmt.Println("Unit not recognized.") |
||||
} |
||||
fmt.Println("Waiting ", duration_int, " ", unit, ".") |
||||
if start.Stop() { |
||||
<-start.C |
||||
fmt.Println("Done waiting ", duration_int, " ", unit, "!") |
||||
} |
||||
return start |
||||
// for elapsed < ten_seconds {
|
||||
//}
|
||||
// for
|
||||
} |
||||
|
||||
func Reset |
Loading…
Reference in new issue