Azure Config Generator
 All Classes Namespaces Files Functions Variables Properties
SpecExtractor.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.IO;
4 using System.Linq;
5 using System.Text;
6 using System.Text.RegularExpressions;
7 using System.Threading.Tasks;
8 using System.Xml;
9 using System.Xml.Linq;
10 
11 namespace FUSE.AzureConfig.Tasks
12 {
13  public class SpecExtractor
14  {
15  public AzureConfigSpec Extract(string configDir)
16  {
17  if (string.IsNullOrEmpty(configDir) || !Directory.Exists(configDir))
18  throw new ArgumentException(configDir + " does not exist");
19  var csdef = Path.Combine(configDir, FileGenerator.CsdefName);
20  if (!File.Exists(csdef))
21  throw new ArgumentException(csdef + " does not exist");
22 
23  var settingsByRole = ProcessCsdef(csdef);
24  var envs = ProcessCscfgs(configDir);
25  return MergeEnvs(envs, settingsByRole);
26  }
27 
28  private IDictionary<string, ISet<string>> ProcessCsdef(string csdef)
29  {
30  var settingsByRole = new Dictionary<string, ISet<string>>();
31  var doc = XDocument.Load(csdef);
32  var rootNS = FileGenerator.GetRootNamespace(doc);
33  var roles = from e in doc.Descendants()
34  where e.Name == rootNS + "WebRole" || e.Name == rootNS + "WorkerRole"
35  select e;
36  foreach (var roleElt in roles)
37  {
38  var roleName = roleElt.Attribute("name").Value;
39  var curSettings = new HashSet<string>();
40  settingsByRole[roleName] = curSettings;
41  var settingElts = roleElt.Element(rootNS + "ConfigurationSettings").Elements(rootNS + "Setting");
42  foreach (var setting in settingElts)
43  {
44  var settingName = setting.Attribute("name").Value;
45  curSettings.Add(settingName);
46  }
47  }
48  return settingsByRole;
49  }
50 
51  private static readonly Regex _CscfgNamePat = new Regex(@"ServiceConfiguration\.(?<env>[^.]+)\.cscfg");
52 
53  private class EnvData
54  {
55  public EnvData()
56  {
57  this.InstancesByRole = new Dictionary<string, int>();
58  this.SettingsByRole = new Dictionary<string, Dictionary<string, string>>();
59  }
60 
61  public string Name { get; set; }
62 
63  public Dictionary<string, int> InstancesByRole { get; set; }
64 
65  public Dictionary<string, Dictionary<string, string>> SettingsByRole { get; set; }
66  }
67 
68  private List<EnvData> ProcessCscfgs(string cscfgsDir)
69  {
70  var envs = new List<EnvData>();
71  var files = Directory.GetFiles(cscfgsDir, "*.cscfg");
72  foreach (var file in files)
73  {
74  var envName = _CscfgNamePat.Match(file).Groups["env"].Value;
75  envName = string.IsNullOrEmpty(envName) ? FileGenerator.DefaultEnvName : envName;
76  var env = new EnvData() { Name = envName };
77  envs.Add(env);
78  var doc = XDocument.Load(file);
79  var rootNS = FileGenerator.GetRootNamespace(doc);
80  var roles = from e in doc.Descendants()
81  where e.Name == rootNS + "Role"
82  select e;
83  foreach (var roleElt in roles)
84  {
85  var roleName = roleElt.Attribute("name").Value;
86  env.SettingsByRole[roleName] = new Dictionary<string, string>();
87  env.InstancesByRole[roleName] = int.Parse(roleElt.Element(rootNS + "Instances").Attribute("count").Value);
88  var settingElts = roleElt.Element(rootNS + "ConfigurationSettings").Elements(rootNS + "Setting");
89  foreach (var setting in settingElts)
90  {
91  var settingName = setting.Attribute("name").Value;
92  var settingVal = setting.Attribute("value").Value;
93  env.SettingsByRole[roleName][settingName] = settingVal;
94  }
95  }
96  }
97  return envs;
98  }
99 
100  private AzureConfigSpec MergeEnvs(List<EnvData> envs, IDictionary<string, ISet<string>> settingsByRole)
101  {
102  var spec = new AzureConfigSpec();
103  var parent = string.Empty;
104  Dictionary<string, Dictionary<string, string>> prev = null;
105  foreach (var env in envs.OrderBy(x => x.Name))
106  {
107  var envSpec = new EnvironmentSpec() { ProfileName = env.Name };
108  spec.Environments[env.Name] = envSpec;
109  foreach (var role in env.InstancesByRole)
110  {
111  envSpec.Roles[role.Key] = new RoleSpec() { Instances = role.Value };
112  }
113  envSpec.Parent = parent;
114  // Only set settings different from "parent"
115  foreach (var role in env.SettingsByRole)
116  {
117  var settings = new Dictionary<string, string>();
118  envSpec.ConfigSettings[role.Key] = settings;
119  foreach (var setting in role.Value)
120  {
121  if (prev == null || !prev.ContainsKey(role.Key)
122  || !prev[role.Key].ContainsKey(setting.Key) || prev[role.Key][setting.Key] != setting.Value)
123  settings[setting.Key] = setting.Value;
124  }
125  }
126 
127  parent = env.Name;
128  prev = env.SettingsByRole;
129  }
130  return spec;
131  }
132  }
133 }
AzureConfigSpec Extract(string configDir)
JSON-based azure configuration specification.