// 2018 Rackspace, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"): you may // not use this file except in compliance with the License. You may obtain // a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the // License for the specific language governing permissions and limitations // under the License. package shutdown import ( "errors" "fmt" "net" "regexp" ) type f5 struct { Opts Options RawConfig string StartupConfig string UpdatedConfig string } func (d *f5) modify() string { d.UpdatedConfig = d.RawConfig d.modifyMgmtInfo() d.modifyVlans() return d.UpdatedConfig } func (d *f5) modifyMgmtInfo() { if d.Opts.MgmtInfo == nil { return } matched, _ := regexp.MatchString("sys management-ip", d.UpdatedConfig) if matched { // 11.x+ code versions re := regexp.MustCompile( fmt.Sprintf( `sys management-ip %s/%d(\b)`, d.Opts.MgmtInfo.IP.Old, d.netmaskToCidr(d.Opts.MgmtInfo.Netmask.Old), )) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf( `sys management-ip %s/%d${1}`, d.Opts.MgmtInfo.IP.New, d.netmaskToCidr(d.Opts.MgmtInfo.Netmask.New), ), ) re = regexp.MustCompile( fmt.Sprintf(`(?s)(sys management-route.*?gateway) %s(\b)`, d.Opts.MgmtInfo.Gateway.Old), ) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf(`${1} %s${2}`, d.Opts.MgmtInfo.Gateway.New), ) re = regexp.MustCompile( fmt.Sprintf(`(?s)(cm device .*?) management-ip %s(\b)`, d.Opts.MgmtInfo.IP.Old), ) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf(`${1} management-ip %s${2}`, d.Opts.MgmtInfo.IP.New), ) re = regexp.MustCompile( fmt.Sprintf( `(?s)(unicast-address .*?) effective-ip %s(\b.*?) ip %s(\b)`, d.Opts.MgmtInfo.IP.Old, d.Opts.MgmtInfo.IP.Old, ), ) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf(`${1} effective-ip %s${2} ip %s${3}`, d.Opts.MgmtInfo.IP.New, d.Opts.MgmtInfo.IP.New), ) } else { // 10.x code versions re := regexp.MustCompile( fmt.Sprintf( `(?s)mgmt %s (.*?) netmask %s(\b)`, d.Opts.MgmtInfo.IP.Old, d.Opts.MgmtInfo.Netmask.Old, ), ) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf( `mgmt %s ${1} netmask %s${2}`, d.Opts.MgmtInfo.IP.New, d.Opts.MgmtInfo.Netmask.New, ), ) re = regexp.MustCompile( fmt.Sprintf(`(?s)(mgmt route .*? gateway) %s(\b)`, d.Opts.MgmtInfo.Gateway.Old), ) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf(`${1} %s${2}`, d.Opts.MgmtInfo.Gateway.New), ) } } func (d *f5) modifyVlans() { if d.Opts.VlanMap == nil { return } for o, n := range d.Opts.VlanMap { re := regexp.MustCompile(fmt.Sprintf(`(?s)((?:net )?vlan.*?) tag %s(\b)`, o)) d.UpdatedConfig = re.ReplaceAllString( d.UpdatedConfig, fmt.Sprintf(`${1} tag %s${2}`, n), ) } } func (d *f5) netmaskToCidr(netmask string) int { nm := net.ParseIP(netmask).To4() size, _ := net.IPv4Mask(nm[0], nm[1], nm[2], nm[3]).Size() return size } func (d *f5) verify() error { if err := d.verifyMgmtInfo(); err != nil { return err } if err := d.verifyVlans(); err != nil { return err } return nil } func (d *f5) verifyMgmtInfo() error { if d.Opts.MgmtInfo == nil { return nil } matched, _ := regexp.MatchString("sys management-ip", d.UpdatedConfig) //nolint re := new(regexp.Regexp) if matched { // 11.x+ code versions re = regexp.MustCompile( fmt.Sprintf( `sys management-ip %s/%d(\b)`, d.Opts.MgmtInfo.IP.New, d.netmaskToCidr(d.Opts.MgmtInfo.Netmask.New), )) } else { // 10.x code versions re = regexp.MustCompile( fmt.Sprintf( `(?s)mgmt %s (.*?) netmask %s(\b)`, d.Opts.MgmtInfo.IP.New, d.Opts.MgmtInfo.Netmask.New, ), ) } if !re.MatchString(d.StartupConfig) { return errors.New("verify(): failure matching on updated mgmt IP") } return nil } func (d *f5) verifyVlans() error { if d.Opts.VlanMap == nil { return nil } vlans := make([]string, 0) for o := range d.Opts.VlanMap { re := regexp.MustCompile(fmt.Sprintf(`(?s)(?:net )?vlan.*? tag %s\b`, o)) if re.MatchString(d.RawConfig) { vlans = append(vlans, o) } } for _, oldVlan := range vlans { re := regexp.MustCompile(fmt.Sprintf(`(?s)(?:net )?vlan.*? tag %s\b`, d.Opts.VlanMap[oldVlan])) if !re.MatchString(d.StartupConfig) { return fmt.Errorf("verify(): failure matching on vlan %s", d.Opts.VlanMap[oldVlan]) } } return nil }