/ ProjectPlugins / GethPlugin / GethContainerInfoExtractor.cs
GethContainerInfoExtractor.cs
  1  using KubernetesWorkflow;
  2  using KubernetesWorkflow.Types;
  3  using Logging;
  4  using Utils;
  5  
  6  namespace GethPlugin
  7  {
  8      public class GethContainerInfoExtractor
  9      {
 10          private readonly ILog log;
 11          private readonly IStartupWorkflow workflow;
 12          private readonly RunningContainer container;
 13  
 14          public GethContainerInfoExtractor(ILog log, IStartupWorkflow workflow, RunningContainer container)
 15          {
 16              this.log = log;
 17              this.workflow = workflow;
 18              this.container = container;
 19          }
 20  
 21          public AllGethAccounts ExtractAccounts()
 22          {
 23              log.Debug();
 24              var accountsCsv = Retry(() => FetchAccountsCsv());
 25              if (string.IsNullOrEmpty(accountsCsv)) throw new InvalidOperationException("Unable to fetch accounts.csv for geth node. Test infra failure.");
 26  
 27              var lines = accountsCsv.Split('\n');
 28              return new AllGethAccounts(lines.Select(ParseLineToAccount).ToArray());
 29          }
 30  
 31          public string ExtractPubKey()
 32          {
 33              log.Debug();
 34              var pubKey = Retry(FetchPubKey);
 35              if (string.IsNullOrEmpty(pubKey)) throw new InvalidOperationException("Unable to fetch enode from geth node. Test infra failure.");
 36  
 37              return pubKey;
 38          }
 39  
 40          private string FetchAccountsCsv()
 41          {
 42              return workflow.ExecuteCommand(container, "cat", GethContainerRecipe.AccountsFilename);
 43          }
 44  
 45          private string FetchPubKey()
 46          {
 47              var enodeFinder = new PubKeyFinder(s => log.Debug(s));
 48              workflow.DownloadContainerLog(container, enodeFinder, null);
 49              return enodeFinder.GetPubKey();
 50          }
 51  
 52          private GethAccount ParseLineToAccount(string l)
 53          {
 54              var tokens = l.Replace("\r", "").Split(',');
 55              if (tokens.Length != 2) throw new InvalidOperationException();
 56              var account = tokens[0];
 57              var privateKey = tokens[1];
 58              return new GethAccount(account, privateKey);
 59          }
 60  
 61          private static string Retry(Func<string> fetch)
 62          {
 63              // This class is the first moment where we interact with our new geth container.
 64              // K8s might be moving pods and/or setting up new VMs.
 65              // So we apply a generous retry timeout.
 66              var retry = new Retry(nameof(GethContainerInfoExtractor),
 67                  maxTimeout: TimeSpan.FromMinutes(15.0),
 68                  sleepAfterFail: TimeSpan.FromSeconds(20.0),
 69                  onFail: f => { },
 70                  failFast: false);
 71  
 72              return retry.Run(fetch);
 73          }
 74      }
 75  
 76      public class PubKeyFinder : LogHandler, ILogHandler
 77      {
 78          private const string openTag = "self=enode://";
 79          private const string openTagQuote = "self=\"enode://";
 80          private readonly Action<string> debug;
 81          private string pubKey = string.Empty;
 82  
 83          public PubKeyFinder(Action<string> debug)
 84          {
 85              this.debug = debug;
 86              debug($"Looking for '{openTag}' in container logs...");
 87          }
 88  
 89          public string GetPubKey()
 90          {
 91              if (string.IsNullOrEmpty(pubKey)) throw new Exception("Not found yet exception.");
 92              return pubKey;
 93          }
 94  
 95          protected override void ProcessLine(string line)
 96          {
 97              debug(line);
 98              if (line.Contains(openTag))
 99              {
100                  ExtractPubKey(openTag, line);
101              }
102              else if (line.Contains(openTagQuote))
103              {
104                  ExtractPubKey(openTagQuote, line);
105              }
106          }
107  
108          private void ExtractPubKey(string tag, string line)
109          {
110              var openIndex = line.IndexOf(tag) + tag.Length;
111              var closeIndex = line.IndexOf("@");
112  
113              pubKey = line.Substring(
114                      startIndex: openIndex,
115                      length: closeIndex - openIndex);
116          }
117      }
118  }