Olá pessoal, sejam muito bem-vindos a mais essa aula. E na aula de hoje nós falaremos sobre as Lifecycle Rules. Para que a gente entenda, nós teremos aqui alguns exemplos onde eu vou utilizar o módulo de Network para simplificar um pouquinho. Então, eu comentei o módulo de Cluster, já dei um terraform e Apply, o que significa que na minha infraestrutura nós temos somente os recursos relacionados ao módulo de redes. Então vamos lá. relacionados ao módulo de redes. Então vamos lá. Eu vou navegar aqui até o arquivo main.df do módulo de network, onde nós temos aqui, por exemplo, o recurso aws-vpc, que pode ser o recurso que nós utilizaremos como exemplo. Sempre que nós precisarmos de criar uma lifecycle rule, nós vamos utilizar o bloco lifecycle dentro do próprio recurso onde nós queremos aplicar aquela regra. E a primeira regra que nós teremos é a regra createBeforeDestroy. Nós podemos utilizar essa regra aqui para o seguinte, imagina que a gente altere aqui o bloco da nossa VPC, a gente mude o VPC CiderBlock. Sempre que nós mudamos esse CiderBlock, o que o Terraform faz é excluir a VPC existente, então criar a nova VPC. E esse é o comportamento do Terraform por default para todos os recursos. Então sempre que há uma alteração, que nós alteramos um atributo de um determinado recurso e que essa alteração obriga o Terraform a excluir o recurso existente e então criar um novo, ele sempre fará nessa ordem, exclui o existente e cria um novo. Porém, em alguns casos isso pode causar uma indisponibilidade da nossa aplicação. Então vamos supor que nós estivéssemos trabalhando aqui com uma máquina virtual, nós alterássemos essa máquina virtual para aumentar o capacite, por exemplo, e essa alteração exigisse que aquela máquina virtual que já está rodando na nossa infraestrutura fosse excluída e a nova fosse criada. Bom, nós teríamos ali um tempo de indisponibilidade da aplicação, que é o tempo entre a exclusão da máquina antiga e a criação da nova. Nós podemos alterar esse comportamento utilizando esse lifecycle que garante que a nova máquina será criada para que então a máquina antiga seja destruída. E aí você pode se questionar, bom, por que esse não é o comportamento padrão do Terraform? Seria muito melhor se ele sempre criasse primeiro os novos recursos e então excluísse os recursos antigos. O problema é que muitas vezes existem algumas restrições na infraestrutura que não permitem, por exemplo, que duas máquinas virtuais com o mesmo nome sejam criadas. Esse aqui foi só um exemplo, eu acho que isso não acontece, na verdade isso não acontece na AWS, mas existem muitos recursos que possuem essas restrições. Então, às vezes você vai criar um bucket no S3, o nome deve ser único. E se você não alterou o nome, você alterou alguma outra coisa, não tem como ele criar primeiro um novo bucket com o mesmo nome e manter esse novo bucket e o bucket ativo com o mesmo nome ao mesmo tempo. Então, é por isso que por default primeiro ele exclui o recurso, então cria um novo para evitar qualquer conflito de configuração, beleza? Mas para casos em que você sabe que isso não vai acontecer e que você quer uma outra disponibilidade da sua infraestrutura, você pode utilizar este Lifecycle, certo? Então, esta daqui é a primeira regra que nós podemos adicionar. Agora nós falaremos também sobre a regra Prevent Destroy. E nós podemos colocar aqui como True ou False, tá? For the full, ela é false. Bom, o nome já sugere, né? Este aqui vai evitar que este recurso seja excluído. Então, como eu já mencionei, existem alterações que fazem com que o recurso seja excluído para então um novo recurso ser criado, que é o caso do CIDER block, mas se nós quisermos evitar qualquer acidente desse tipo, vamos supor que a gente esteja trabalhando aqui com banco de dados que nunca pode ser excluído. Então, uma vez que eu crio o banco de dados e já estou utilizando esse banco de dados, eu não quero que nenhuma alteração no banco de dados faça com que ele seja excluído. Então, às vezes pode acontecer ali, alguém modificou alguma configuração, achou que era só modificar e que o update aconteceria em place, mas na verdade aquele update poderia fazer com que o banco de dados fosse excluído e a pessoa não percebeu. Colocando esse lifecycle aqui, prevent, destroy, nós temos a garantia de que esse tipo de acidente não vai acontecer. Para nós vermos aqui um exemplo, nós podemos navegar até o nosso Terraform TF Vars, onde nós definimos as nossas variáveis, nós podemos mudar o Cider Block da nossa V VPC e agora nós temos aqui o nosso prevent destroy e quando nós rodarmos Terra Farm Plane nós verificaremos aqui que nós teremos uma mensagem de erro porque a alteração do CIDER block ela requer que a VPC seja excluída mas nós temos aqui um prevent destroy e aqui nós podemos ver a inst instância não pode ser destruída porque nós temos esse prevent destroy setado, beleza? Então, nós já entendemos como funciona o prevent destroy. Vamos navegar aqui de novo, voltar o valor para 16, tá? Caso a gente precise alterar, depois a gente altera de novo. Agora, nós teremos aqui também um outro lifecycle que é o ignoreChanges. Deixa eu colocar ele aqui. Nós aqui ao invés de passarmos pro false, nós vamos passar uma lista de atributos. Então nós podemos passar aqui tags, que é um dos atributos desse recurso. Poderíamos passar sideBlock também, poderíamos colocar aqui dividido por vírgula Mas por enquanto Ou poderíamos na verdade Colocar all também Que vai se aplicar a todos os atributos Por enquanto eu vou comentar Eu gostaria de mostrar aqui um exemplo Do que acontece quando nós alteramos Alguma coisa, algum dos nossos recursos De forma manual Isso é algo que não é recomendado Então sempre que você está trabalhando com terraform Procure gerenciar todos os seus recursos, todas as propriedades, qualquer alteração através do terraform. Procure não fazer nada manualmente. Mas existem alguns casos em que há um processo, às vezes, automatizado, fora do terraform, que faz alteração nos nossos recursos. Por exemplo, poderia haver um processo automatizado na sua empresa que percorre todos os recursos criados na sua infraestrutura e quando ele identifica um recurso que não possui a tag environment, por exemplo ele adiciona automaticamente essa tag colocando aqui o valor de prod por exemplo, então essa automação fez isso colocou aqui essa nova tag environment dentro do seu recurso e essa tag não está definida no nosso recurso em Terraform. Bom, quando nós damos um Terraform plain ou um Terraform apply, quando nós vamos aplicar qualquer alteração aqui no nosso Terraform, vamos supor que a gente alterou o nosso cluster, por exemplo, mas quando nós aplicarmos, ele vai fazer o refresh do state e ele vai identificar que existe uma nova tag, uma tag environment, que não está no nosso state. Então ele vai adicionar essa tag ao nosso state, porém ele identifica que aqui no nosso arquivo de configuração nós não temos essa tag. Então ele entende que essa tag deve ser excluída. Então nós vamos acabar excluindo aquela tag que foi adicionada para aquela automação. Mas, às vezes, isso não é o comportamento que a gente quer. Então nós podemos utilizar o IgnoreChanges para esses cenários. Então nós poderíamos colocar aqui, por exemplo, tags. Sempre que identificar uma alteração vinda de fora, uma alteração foi realizada manualmente, fora do escopo do Terraform, nesses campos aqui especificados nessa lista, o terraform vai ignorar essas alterações, tá? Então quando nós especificamos essa forma e salvamos e rodamos aqui novamente o nosso terraform plan, nós veremos aqui que não haverá nada a ser alterado, tá? Por causa desse lifecycle. Vamos esperar que seja rodado o comando de play e aqui temos noChange, beleza? Então entendemos aqui já como funciona o nosso ignoreChange. Por fim temos aqui uma última regra que é o replace triggeredBy, tá? Vamos, deixa eu ver aqui um exemplo que nós podemos fazer. Na verdade, eu vou navegar aqui até um outro componente para a gente entender algo que nós podemos, um exemplo que nós podemos fazer. Vamos supor aqui que a gente altere o nosso Security Group, altere uma tag do nosso Security Group, coloque HTTP. Então, vamos fazer este exemplo. E aqui, um recurso que não tem nada a ver com esse Security Group, por exemplo, o nosso Internet Gateway, a gente queira uma regra, a gente queira aqui um Lifecycle Rule, e sempre que houver uma alteração do nosso Security Group, esse Internet Gateway seja substituído. Bom, não tem nada a ver, não tem relação uma coisa com a outra, mas em alguns cenários onde há uma dependência não explícita, nós podemos utilizar esse Replace Triggered By, que é o seguinte, nós podemos especificar aqui uma lista, dizendo que sempre que houver, então, uma alteração qualquer dentro desse Security Group, nós vamos substituir o nosso Internet Gateway, certo? Então, vamos ver esse exemplo, tá? Para ficar claro. Vamos rodar aqui o Terraform Plan. Eu alterei somente a tag, somente a tag aqui do nosso Security Group, então deveria somente alterar o nosso Security Group, tá? security group, então deveria somente alterar o nosso security group, tá? Porém, quando nós fizemos isso, nós alteramos aqui, tem já no nosso plan a alteração prevista para o security group, porém, o que ele faz aqui? Ele vai atualizar também a nossa route table e vai atualizar também o nosso internet gateway, tá? Por que ele atualiza a route table? Porque nós temos aqui um replace do internet gateway e este? Por que ele atualiza a route table? Porque nós temos aqui um replace do internet gateway, e este replace acontece por causa do replace triggered by, e quando nós substituímos o internet gateway, nós precisamos também atualizar a nossa route table para apontar para esse novo internet gateway. Então, dessa forma, nós estamos encadeando aqui as dependências entre os nossos recursos, Brancadeando aqui as dependências entre os nossos recursos, porque às vezes há recursos que sempre que eles são alterados, você queira de fato substituir um outro recurso, porque eles têm ali uma dependência implícita que o Terraform não consegue identificar. Então isso é bastante interessante. Você pode especificar aqui vários outros componentes e você pode inclusive especificar um campo específico. outros componentes e você pode inclusive especificar um campo específico. Então, vamos supor que a gente queira fazer esse replace do Internet Gateway somente quando um novo Security Group for criado. Então, nesse caso, nós poderíamos colocar aqui ID, porque se nós colocamos ID, o ID só muda quando um novo recurso é criado, quando um recurso é excluído e então criado. Quando nós colocamos o id, aí nós podemos rodar o plane de novo aqui beleza, nós não precisamos de alterar o security group, porque a única coisa que foi alterada foi o nome, então nós não precisamos de criar um novo security group e agora neste novo terraform plane nós vemos que o único recurso que precisa ser alterado é o security group o nosso gateway aqui ele não precisa ser substituído, porque ele está apontando somente para o ID. Ele só será substituído quando o ID do Security Group for alterado, beleza? Então, temos aqui já mais uma regra de Lifecycle Rule que nós entendemos, né? Uma regra de Lifecycle. Beleza? Voltando até o normal, em termos de regras, basicamente são essas, tá? Porém, nós temos também algumas outras coisas que nós podemos adicionar no nosso life cycle, que são as pre-conditions e as post-conditions, tá? As post-conditions. Eu vou copiar aqui um exemplo para que a gente analise este exemplo. Então nós temos aqui uma precondition que é o seguinte, olha aqui nós estamos verificando que o nosso CIDER block, o bloco aqui do nosso CIDER, ele precisa ser maior do que 18, sempre maior do que 18 não pode ser menor do que barra 18 então nesse caso nós criamos aqui uma função, nós estamos dividindo o nosso CIDER block, dando um split aqui no barra, pegando somente a segunda parte da nossa string, que corresponde ao 16 aqui no nosso test vars, por exemplo, corresponde a essa parte aqui, o 16, transformamos em número e verificamos que é maior que 18, tá? E aqui nós especificamos uma mensagem. Então, sempre que nós formos rodar aqui o nosso Terraform Apply, se ele identificar uma alteração que conflita com essa regra aqui, ele vai dar uma mensagem de erro. Então, nós podemos verificar isso rodando aqui o Terraform Play. Nós vamos identificar o que acontece. Bom, eu não sei se eu salvei, né? Deixa eu salvar aqui. Beleza. Você vai dar uma refresh no state. E aqui nós temos o nosso resource precondition failed, por quê? Porque nós temos um barra 16, resource precondition failed. Por quê? Porque nós temos um barra 16, mas a condição aqui requer que seja um barra 18. Nós utilizamos esse precondition para que o Terraform faça a análise da condição antes de aplicar qualquer alteração, antes de trabalhar de fato em cima daquele recurso. E nesse precondition a gente não consegue fazer uma referência direta ao próprio recurso. Então, geralmente nós utilizamos aqui o precondition para nós verificarmos alguma variável ou algum outro recurso. Quando há uma precondição relacionada a algum outro recurso, nós poderíamos colocar aqui, por exemplo, a referência ao nosso data source, ao nosso availability zone. Se há uma condição aqui que não pode ser criada essa VPC numa região com menos de quatro availability zones, algum exemplo do tipo. Então nós utilizamos pre-condition para isso. Porém nós podemos ter post-conditions, para quando nós queremos verificar as próprias propriedades do recurso. E as condições do post-condition são calculadas, são verificadas após as alterações no do recurso. E as condições do Post Conditions são calculadas, são verificadas após as alterações no próprio recurso. Após o Terraform identificar o que precisa ser alterado naquele recurso. Como por exemplo, nós poderíamos ter aqui essa Post Conditions que define o seguinte, olha, é necessário que a gente tenha aqui uma Tag environment. Esse recurso precisa ter a tag environment. Para nós referenciarmos o próprio recurso, nós utilizamos o self. Esse self não é permitido dentro do pre-condition, somente dentro da post-condition. Deixa eu alterar aqui o nosso tf-vars para a barra 20, só para nós verificarmos aqui se nós passamos o nosso pre-condition e verificarmos se nós temos um erro no nosso postcondition. Vamos aguardar aqui novamente, sempre demora um pouquinho, porque nós temos esse state lock, o nosso state está remoto, nós temos um backend remoto, e aqui nós temos, nós vemos que o nosso, somente o nosso postcondition que falhouhou e aqui o problema é porque tags não possuem essa tag environment, se nós adicionarmos a tag esse post condition agora ele será calculado com sucesso terá a evaluation dele retornando um sucesso e aí nós podemos criar nosso recurso sem problema nenhum, beleza? então em termos de lifecycle é isso que nós precisávamos aprender. Já vimos todas as regras disponíveis e falamos também sobre Preconditions e Postconditions. Eu espero que você tenha gostado. Vejo você na nossa próxima aula.